﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using ProjectBot.Managers;
using MetaBuilders.Irc.Messages;
using MetaBuilders.Irc.Network;
using MetaBuilders.Irc;
using System.Xml;
using ProjectBot.Events;

namespace ProjectBot
{
    public partial class ProjectBot : Form
    {
        #region Fields and Properties
        static ProjectBot This { get; set; }
        private Client client;
        string Host { get; set; }
        string Channel { get; set; }
        string BotNick { get; set; }
        private MonitorFeed FeedMonitor { get; set; }
        private System.Windows.Forms.Timer CheckFeeds { get; set; }
        private RssFeedReader Reader = new RssFeedReader();
        private List<string> PreviousConsoleCommands = new List<string>();
        #endregion
        #region Constructor
        public ProjectBot()
        {
            This = this;
            InitializeComponent();
            CheckFeeds = new Timer();
            CheckFeeds.Tick += new EventHandler(CheckFeeds_Tick);
            this.FormClosing += new FormClosingEventHandler(ProjectBot_FormClosing);
            this.txt_CommandBox.KeyDown += new KeyEventHandler(txt_CommandBox_KeyDown);
            XMLManager.AddFeed("projectircbot");
        }
        #endregion
        #region Timers
        private void CheckFeeds_Tick(object sender, EventArgs e)
        {
            int newInterval = 0;
            int.TryParse(txt_Interval.Text+"000", out newInterval);
            if (newInterval == 0) { newInterval = 10000; } // 10 second default
            CheckFeeds.Interval = newInterval;
            foreach (string feed in XMLManager.GetAllFeedNames())
            {
                FeedMonitor = new MonitorFeed(feed);
                FeedMonitor.changeDetected += new MonitorFeed.ChangeDetected(FeedMonitor_changeDetected);
            }

        }
        #endregion
        #region WriteLine
        public static void WriteLine(string msg)
        {
            if (This.rtfOutput.InvokeRequired)
            {
                This.Invoke((MethodInvoker)
                    delegate
                    {
                        This.rtfOutput.AppendText(msg + "\n");
                    });
            }
            else
            {
                This.rtfOutput.AppendText(msg + "\n");
            }
        }
        public static void WriteLine(string msg, Color color)
        {
            if (This.rtfOutput.InvokeRequired)
            {
                This.Invoke((MethodInvoker)
                    delegate
                    {
                        This.rtfOutput.SelectionColor = color;
                        This.rtfOutput.AppendText(msg + "\n");
                    });
            }
            else
            {
                This.rtfOutput.SelectionColor = color;
                This.rtfOutput.AppendText(msg + "\n");
            }
        }
        #endregion
        #region Load
        private void ProjectBot_Load(object sender, EventArgs e)
        {
            // Make sure our config dir is there
            if (!Directory.Exists(Globals.AppDir)) { Directory.CreateDirectory(Globals.AppDir); }
            // Initilize our config file.
            XMLManager.Load();
        }
        #endregion
        #region Connect
        private void btn_Connect_Click(object sender, EventArgs e)
        {
            if (txt_Servername.Text == string.Empty) { return; }
            if (txt_Channel.Text == string.Empty) { return; }
            if (txt_BotNick.Text == string.Empty) { return; }
            Host = txt_Servername.Text;
            Channel = txt_Channel.Text;
            BotNick = txt_BotNick.Text;
            client = new Client(Host, txt_BotNick.Text, "A ProjectBot");

            Ident.Service.User = this.client.User;
            // Once I'm welcomed, I can start joining channels
            client.Messages.Welcome += new EventHandler<IrcMessageEventArgs<WelcomeMessage>>(welcomed);

            // People are chatting, pay attention so I can be a lame echobot :)
            client.Messages.Chat += new EventHandler<IrcMessageEventArgs<TextMessage>>(chatting);

            client.Messages.TimeRequest += new EventHandler<IrcMessageEventArgs<TimeRequestMessage>>(timeRequested);

            client.DataReceived += new EventHandler<ConnectionDataEventArgs>(dataGot);
            client.DataSent += new EventHandler<ConnectionDataEventArgs>(dataSent);

            client.Connection.Disconnected += new EventHandler<ConnectionDataEventArgs>(logDisconnected);

            client.EnableAutoIdent = false;

            // Since I'm a Windows.Forms application, i pass in this form to the Connect method so it can sync with me.
            try
            {
                client.Connection.Connect(this);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            // Start Monitoring
            try
            {
                CheckFeeds.Start();
            }
            catch { WriteLine("Error Starting feed monitoring!!!!!", Color.Red); }
        }
        #endregion
        #region Events
        private void FeedMonitor_changeDetected(object sender, ChangeArgs e)
        {
            // report the change to our channel and Screen
            List<string> msg = new List<string>();
            msg.Add("**********************");
            msg.Add(e.Project.ProjectName.ToUpperInvariant() + " Updated: " + e.Project.Updated);
            msg.Add(e.Project.Link);
            msg.Add(e.Project.Description);
            msg.Add("Offender: " + e.Project.Author);
            msg.Add("**********************");
            if (client != null)
            {
                foreach (string line in msg)
                {
                    ProjectBot.WriteLine(line, Color.Magenta);
                    if (chk_ReportToIrc.Checked) { client.SendChat(line, Channel); }
                }
            }
        }
        private void logDisconnected(Object sender, ConnectionDataEventArgs e)
        {
            String data = "*** Disconnected: " + e.Data;
            WriteLine(data, Color.Red);
        }

        private void dataGot(Object sender, ConnectionDataEventArgs e)
        {
            String data = "<-" + e.Data;
            WriteLine(data);
        }

        private void dataSent(Object sender, ConnectionDataEventArgs e)
        {
         //   this.textBox1.Text += "->" + e.Data + System.Environment.NewLine;
           // this.textBox1.Select(this.textBox1.Text.Length - 1, 1);
           // this.textBox1.ScrollToCaret();
        }

        private void chatting(Object sender, IrcMessageEventArgs<TextMessage> e)
        {
            //if (e.Message.Text.StartsWith(BotNick))
            //{
            string[] args = e.Message.Text.Split(' ');
            if (args.Length > 1)
            {
                if (args[0].ToLower() == BotNick.ToLower())
                {
                    string reply = string.Empty;
                    // I am being talked to, what am i being asked ?
                    if (args.Length >= 2)
                    {
                        switch (args[1].ToLower())
                        {
                            case "addfeed":
                                {
                                    string addfeed_reply = string.Empty;
                                    // we need a feedname otherwise give help for the command
                                    if (args.Length != 3)
                                    {
                                        addfeed_reply = "Correct use of this command: addfeed projectname, the projectname must be a valid googlecode project";
                                        return;
                                    }
                                    else // we have a project
                                    {
                                        XmlDocument doc = null;
                                        Reader.TryRead(Globals.GetProjectLink(args[2]), out doc);
                                        if (doc == null) { return; }
                                        XMLManager.AddFeed(args[2]);
                                        addfeed_reply = "Feed added to monitor";
                                    }
                                    client.SendChat(addfeed_reply, Channel);

                                }
                                break;
                            case "removefeed":
                                {
                                    string removeFed_reply = string.Empty;
                                    if (args.Length != 3)
                                    {
                                       removeFed_reply = "Correct use of this command: removefeed projectname, the projectname must be a valid googlecode project";
                                        return;
                                    }
                                    try
                                    {
                                        if (!ProjectManager.IsContained(args[2])) { return; }
                                        XMLManager.RemoveFeed(args[2]);
                                        ProjectManager.RemoveProject(args[2]);
                                        reply = "Project " + args[2] + " removed.";
                                    }
                                    catch { reply = "Error attempting to remove project!!"; }
                                }
                                break;
                            case "help":
                                reply = "help here";
                                break;
                            default:
                                reply = "No known command.";
                                break;
                        }
                        if (reply != string.Empty) { client.SendChat(reply, Channel); }
                    }
                }
            }
        }

        private void timeRequested(Object sender, IrcMessageEventArgs<TimeRequestMessage> e)
        {
            MetaBuilders.Irc.Messages.TimeReplyMessage reply = new MetaBuilders.Irc.Messages.TimeReplyMessage();
            reply.CurrentTime = DateTime.Now.ToLongTimeString();
            reply.Target = e.Message.Sender.Nick;
            client.Send(reply);
        }

        private void welcomed(Object sender, IrcMessageEventArgs<WelcomeMessage> e)
        {
            client.SendJoin(Channel);
        }

        private void SayIt_Click(object sender, System.EventArgs e)
        {
            // change the first channel to text to send
            client.SendChat(Channel, Channel);
            //this.ChatEntry.Text = "";
        }

        private void SendIt_Click(object sender, System.EventArgs e)
        {
            MetaBuilders.Irc.Messages.GenericMessage msg = new MetaBuilders.Irc.Messages.GenericMessage();
            //if (msg.CanParse(this.ChatEntry.Text))
            //{
             //   msg.Parse(this.ChatEntry.Text);
              //  client.Send(msg);
            //}
            //else
            //{
            //    MessageBox.Show("Cannot Parse Your Command.");
            //}
        }
        #endregion
        #region Disconnect
        private void btn_Disconnect_Click(object sender, EventArgs e)
        {
            if (client != null)
            {
                client.SendQuit("I'm Outa Here");
                // stop monitoring
                CheckFeeds.Stop();
            }
        }
        private void ProjectBot_FormClosing(object sender, FormClosingEventArgs e)
        {
            // Stop this timer
            CheckFeeds.Stop();
        }
        #endregion
        #region Command Box
        private void txt_CommandBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                e.SuppressKeyPress = true;
                // if this line exists we are typing it again, so move it to the recent spot
                AddRecentCommand(txt_CommandBox.Text);
                this.btn_Send_Click(sender, e);
            }
            if (e.KeyCode == Keys.Up)
            {
                try
                {
                    txt_CommandBox.Text = PreviousConsoleCommands[GetCurrentCommandSelection(txt_CommandBox.Text) - 1];
                }
                catch { }
            }
            if (e.KeyCode == Keys.Down)
            {
                if (txt_CommandBox.Text == string.Empty)
                {
                    try
                    {
                        txt_CommandBox.Text = PreviousConsoleCommands[PreviousConsoleCommands.Count];
                    }
                    catch { }
                }
                // Get the current spot in our list
                try
                {
                    txt_CommandBox.Text = PreviousConsoleCommands[GetCurrentCommandSelection(txt_CommandBox.Text) + 1];
                }
                catch { }
            }
        }
        private int GetCurrentCommandSelection(string command)
        {
            int reply = 0;
            for (int i = 0; i < PreviousConsoleCommands.Count; i++)
            {
                if (command.ToLower() == PreviousConsoleCommands[i].ToLower())
                {
                    reply = i;
                }
            }
            return reply;
        }
        public void AddRecentCommand(string command)
        {
            int index = GetCurrentCommandSelection(command);
            try
            {
                PreviousConsoleCommands.Remove(txt_CommandBox.Text);
                PreviousConsoleCommands.Add(txt_CommandBox.Text);
            }
            catch { WriteLine("Error in addingrecent", Color.Red); }
        }
        #endregion
        #region Console Command
        private void btn_Send_Click(object sender, EventArgs e)
        {
            //// get the string of the command
            if(!PreviousConsoleCommands.Contains(txt_CommandBox.Text))
            {
                PreviousConsoleCommands.Add(txt_CommandBox.Text);
            }
            // Break it down to an array
            string[] args = txt_CommandBox.Text.Split(' ');
            // Run our switch
            if (args.Length > 0)
            {
                switch (args[0])
                {
                    default:
                        {
                            WriteLine("No Such Command! "+args[0], Color.Red);
                        }
                        break;
                }
            }
        }
        #endregion
    }
}
